//
// Created by chenlei on 2/5/16.
//

#include "NetClient.h"
#include "Kit.h"

/**
 * 初始化函数列表(注意声明顺序)
 */
NetClient::NetClient(EventLoop *loop,
                     const InetAddress &serverAddr,
                     const string &clientName, unsigned char _linkSign)
        : eventLoop(loop),
          tcpClient(loop, serverAddr, clientName),
          linkSign(_linkSign) {
    //enable retry to connect
    //default is not effective
    tcpClient.enableRetry();


    //init logic handle
    pthread_mutex_init(&work_mutex, NULL);
}

/**
 *
 */
NetClient::~NetClient() {
    pthread_mutex_destroy(&work_mutex);
}


/**
 * 连接上服务器
 */
void NetClient::onConnection(const TcpConnectionPtr &conn) {
    if (conn->connected()) {
        LOG_DEBUG << conn->localAddress().toIpPort() << " -> "
                  << conn->peerAddress().toIpPort() << " is "
                  << (conn->connected() ? "UP" : "DOWN");
        connectionPtr = conn;
        connectionPtr->setTcpNoDelay(true);
    } else {
        //disconnect reset it
        connectionPtr.reset();
    }
}

#include "math.h"

/**
 * 网络消息解码
 */
void NetClient::decode(const TcpConnectionPtr &conn, Buffer *in, Timestamp time) {
    unsigned int len = static_cast<unsigned int>(in->readableBytes());
    while (len >= 4) {
        //get frame length
        unsigned int frameLength = static_cast<int>(in->peekInt32());// 包体长度  (4+16+消息长度)
        // never overflows because it's less than maxFrameLength
        unsigned int frameLengthInt = frameLength;
        //current data less frameLengthInt
        unsigned int current = static_cast<unsigned int>(in->readableBytes());
        if (current < frameLengthInt) {
            return;
        }
        //skip package  of length  ,the readerIndex+1
        in->retrieve(4);
        //read  header info
        int cmd = in->readInt16();// 命令码
        int serialNumber = in->readInt32();//协议版本号  n
        int timestamp = in->readInt32();//时间戳
        short versionNumber = in->readInt16();//版本号

        unsigned int msgCRC32 = static_cast<unsigned int>(in->readInt32());//校验码
        //handle actual data
        unsigned int actualFrameLength = frameLengthInt - 20; //实际数据长度
        //消息体
        Buffer buffer;
        buffer.append(in->peek(), actualFrameLength);

        printf("actualFrameLength:%d ,frameLengthInt:%d \n", actualFrameLength, frameLengthInt);

        string message(buffer.peek(), actualFrameLength);



        //some logic
        if (msgCRC32 == calculateCrc32(buffer.peek(), actualFrameLength)) {

            LOG_DEBUG << "---cmd:" << cmd
                      << "\nserialNumber:" << serialNumber
                      << "\ntimestamp:" << timestamp
                      << "\nversionNumber:" << versionNumber
                      << "\nmsgCRC32:" << msgCRC32
                      << "\n comment:" << message;
        }
        in->retrieve(actualFrameLength);
        //next time will try to decode
        len = in->readableBytes();
    }
}

/**
 *
 */
void NetClient::disConnection() {
    tcpClient.disconnect();
}


/**
 * 初始化 客户端 网络服务
 */
void NetClient::start() {
    //bind connection
    tcpClient.setConnectionCallback(boost::bind(&NetClient::onConnection, this, _1));
    tcpClient.setMessageCallback(boost::bind(&NetClient::decode, this, _1, _2, _3));

    //connect server
    tcpClient.connect();
    //loop , never stop
    eventLoop->loop();
}

/**
 * muduo 发送消息接口
 */
void NetClient::writeAndFlush(Buffer *message) {
    if (connectionPtr->connected()) {
        connectionPtr->send(message);
    }
}


/**
 * 测试网络解包处理
 */
void NetClient::test_decode_message(const TcpConnectionPtr &conn, Buffer *buf, Timestamp time) {
    size_t len = buf->readableBytes();
    //begin to decode message
    while (len >= 4) {
        size_t package_length = buf->peekInt32();
        if (len - 4 >= package_length) {
            buf->retrieve(4);


            Buffer buffer;
            buffer.append(buf->peek(), package_length);
            buf->retrieve(package_length);

            //do some logic
            string get_message(buffer.peek(), buffer.forEachByte(0));
            LOG_DEBUG << "get message from server:" << get_message;
            //next time to decode
            len = buf->readableBytes();

            //clear data
            //ack client,add package length
            buffer.prependInt32(buffer.readableBytes());
//            conn->send(&message);
            buffer.retrieveAll();
        } else {
            return;
        }
    }

}


#include "time.h"

int main(int argc, char *argv[]) {

    //seconds
    time_t now;
    time(&now);
    printf("current time stamp:%li, time(0):%li\n", now, time(0));

    //时间戳 格式化
    char formate_time[32];
    strftime(formate_time, sizeof(32),"%Y-%m-%d %H:%M:%S",localtime(&now));
    printf("当前日期:%s \n",formate_time);

    //格式化 转时间戳






    //set debug level
    Logger::setLogLevel(Logger::DEBUG);


    LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid();
    if (argc > 1) {
        EventLoop loop;
        InetAddress serverAddr(argv[1], 8087);
        const string client_ = "test";
        NetClient netClient(&loop, serverAddr, client_, 1);
        netClient.start();//
    }
    else {
        printf("Usage: %s host_ip [msg_size]\n", argv[0]);
    }

    return 0;
}

/***
 * 心跳  登陆成功之后 调用   ----  链路层
 */
void NetClient::heart_beat() {

}

/**
 * 用于处理逻辑数据分发
 */
void NetClient::dispatcher() {

}
